package com.df.my_net_game.net;

import com.baidu.bjf.remoting.protobuf.Codec;
import com.baidu.bjf.remoting.protobuf.ProtobufProxy;
import com.df.my_net_game.proto.equip.C2G_EquipUpLevel;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.timeout.IdleStateHandler;

import java.net.URI;
import java.util.concurrent.TimeUnit;

public class WsClient {
    public static void main(String[] args) throws Exception {
//        WsClient2 wsc = new WsClient2();
//        wsc.url = "ws://localhost:9191/game";
//        wsc.connect();
//        System.out.println(1);
        Codec<C2G_EquipUpLevel> codec = ProtobufProxy.create(C2G_EquipUpLevel.class);

    }
    public static void getWebsocketClient(String url) throws Exception {





    }

    private static class WsClient2{
        Bootstrap bootstrap;
        String url= null;
        Channel channel = null;
        WsClient2() {
            // client端，引导client channel启动
            bootstrap = new Bootstrap();
            // 添加管道 绑定端口 添加作用域等
            bootstrap.group(new NioEventLoopGroup()).channel(NioSocketChannel.class);
        }

        public void onConnect(){}
        public void onClose(){
            //重试机制
        }
        public void onError(Throwable e){
            //重试机制
        }

        public void send(String msg){
            if(channel == null || !channel.isOpen() || !channel.isActive()){
                return;
            }
            channel.writeAndFlush(new TextWebSocketFrame(msg));
        }
        public void send(byte[] msg){
            if(channel == null || !channel.isOpen() || !channel.isActive()){
                return;
            }
            channel.writeAndFlush(new BinaryWebSocketFrame(channel.alloc().heapBuffer().writeBytes(msg)));
        }

        public void onMsg(String msg){

        }

        public void onMsg(byte[] msg){

        }

        public void connect() throws Exception {
            if(url==null){
                throw new RuntimeException("url is null");
            }
            WsClient2 cc = this;
            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(new URI(url), WebSocketVersion.V13, null, true, new DefaultHttpHeaders());
                    WebSocketClientHandler webSocketClientHandler = new WebSocketClientHandler(handshaker,cc);
                    socketChannel.pipeline().addLast(new HttpClientCodec());
                    socketChannel.pipeline().addLast(new HttpObjectAggregator(65536));
                    socketChannel.pipeline().addLast(new WebSocketClientProtocolHandler(handshaker,true,false));
                    socketChannel.pipeline().addLast(new IdleStateHandler(30, 30, 60, TimeUnit.SECONDS));
                    socketChannel.pipeline().addLast(webSocketClientHandler);
                }
            });

            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1",9191);
            // 在连接关闭后尝试重连
            channelFuture.addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if(channelFuture.isSuccess()){
                        onConnect();
                    }else {
                        onError(channelFuture.cause());
                    }
                }
            });
            channelFuture.channel().closeFuture().addListener(future -> {
//                try {
//                    if (heartbeatThread != null && heartbeatThread.isAlive()) {
//                        System.out.println("停止发送心跳线程");
//                        heartbeatThread.close();
//                    }
//                    Thread.sleep(2000);
//                    System.out.println("重新连接服务端");
//                    connect(ip, port, name); // 重新连接服务端
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
            });

            channelFuture.sync();

            channel = channelFuture.channel();
//            System.out.println(name + " 已启动");

            // 定时发送心跳
//            heartbeatThread = new HeartbeatThread(channel);
//            heartbeatThread.start();

            //对通道关闭进行监听
            channelFuture.channel().closeFuture().sync();
        }
    }


    private static class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
        private WebSocketClientHandshaker handshaker;
        private ChannelPromise handshakeFuture;
        private WsClient2 wsClient;

        public WebSocketClientHandler(WebSocketClientHandshaker handshaker,WsClient2 wsClient) {
            this.handshaker = handshaker;
            this.wsClient = wsClient;
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
            if (!handshaker.isHandshakeComplete()) {
                try {
                    handshaker.finishHandshake(ctx.channel(), (FullHttpResponse) msg);
                    handshakeFuture.setSuccess();
                } catch (WebSocketHandshakeException e) {
                    handshakeFuture.setFailure(e);
                }
                return;
            }

            if (msg instanceof PongWebSocketFrame) {
                System.out.println("收到服务端" + ctx.channel().remoteAddress() + "发来的心跳：PONG");
            }

            if (msg instanceof TextWebSocketFrame) {
                TextWebSocketFrame frame = (TextWebSocketFrame) msg;
                System.out.println("收到服务端" + ctx.channel().remoteAddress() + "发来的消息：" + frame.text()); // 接收服务端发送过来的消息
            }

        }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) {
            handshakeFuture = ctx.newPromise();
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) {

        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            System.out.println("客户端下线");
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.flush();
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            ctx.close();
        }
    }
}
